# load necessary packages
library(tidyverse)
── Attaching packages ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.3.0 ──
✔ ggplot2 3.2.1     ✔ purrr   0.3.3
✔ tibble  2.1.3     ✔ dplyr   0.8.3
✔ tidyr   1.0.2     ✔ stringr 1.4.0
✔ readr   1.3.1     ✔ forcats 0.5.0
── Conflicts ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
library(mosaic)
Loading required package: lattice
Loading required package: ggformula
Loading required package: ggstance

Attaching package: ‘ggstance’

The following objects are masked from ‘package:ggplot2’:

    geom_errorbarh, GeomErrorbarh


New to ggformula?  Try the tutorials: 
    learnr::run_tutorial("introduction", package = "ggformula")
    learnr::run_tutorial("refining", package = "ggformula")
Loading required package: mosaicData
Loading required package: Matrix

Attaching package: ‘Matrix’

The following objects are masked from ‘package:tidyr’:

    expand, pack, unpack


The 'mosaic' package masks several functions from core packages in order to add 
additional features.  The original behavior of these functions should not be affected by this.

Note: If you use the Matrix package, be sure to load it BEFORE loading mosaic.

Attaching package: ‘mosaic’

The following object is masked from ‘package:Matrix’:

    mean

The following objects are masked from ‘package:dplyr’:

    count, do, tally

The following object is masked from ‘package:purrr’:

    cross

The following object is masked from ‘package:ggplot2’:

    stat

The following objects are masked from ‘package:stats’:

    binom.test, cor, cor.test, cov, fivenum, IQR, median, prop.test, quantile, sd, t.test, var

The following objects are masked from ‘package:base’:

    max, mean, min, prod, range, sample, sum
library(DataComputing)
library(ggplot2)

Guiding Question

What factors are common between all hall of fame MLB baseball players?

Purpose

This document is required to indicate where various requirements can be found within your Final Project Report Rmd. You must indicate line numbers as they appear in your final Rmd document accompanying each of the following required tasks. Points will be deducted if line numbers are missing or differ signficantly from the submitted Final Rmd document.

Final Project Requirements

Data Access

Description: (1) Analysis includes at least two different data sources. (2) Primary data source may NOT be loaded from an R package–though supporting data may. (3) Access to all data sources is contained within the analysis. (4) Imported data is inspected at beginning of analysis using one or more R functions: e.g., str, glimpse, head, tail, names, nrow, etc

  1. .Rmd Line numbers where at least two different data sources are imported:
HallOfFame <- read_csv("core/HallOfFame.csv")
Parsed with column specification:
cols(
  playerID = col_character(),
  yearID = col_double(),
  votedBy = col_character(),
  ballots = col_double(),
  needed = col_double(),
  votes = col_double(),
  inducted = col_character(),
  category = col_character(),
  needed_note = col_character()
)
AllstarFull <- read_csv("core/AllstarFull.csv")
Parsed with column specification:
cols(
  playerID = col_character(),
  yearID = col_double(),
  gameNum = col_double(),
  gameID = col_character(),
  teamID = col_character(),
  lgID = col_character(),
  GP = col_double(),
  startingPos = col_double()
)
Salaries <- read_csv("core/Salaries.csv")
Parsed with column specification:
cols(
  yearID = col_double(),
  teamID = col_character(),
  lgID = col_character(),
  playerID = col_character(),
  salary = col_double()
)
Batting <- read_csv("core/Batting.csv")
Parsed with column specification:
cols(
  .default = col_double(),
  playerID = col_character(),
  teamID = col_character(),
  lgID = col_character(),
  IBB = col_logical(),
  HBP = col_logical(),
  SH = col_logical(),
  SF = col_logical()
)
See spec(...) for full column specifications.
87292 parsing failures.
 row col           expected actual               file
1999 HBP 1/0/T/F/TRUE/FALSE      2 'core/Batting.csv'
2001 HBP 1/0/T/F/TRUE/FALSE      2 'core/Batting.csv'
2020 HBP 1/0/T/F/TRUE/FALSE      2 'core/Batting.csv'
2022 HBP 1/0/T/F/TRUE/FALSE      2 'core/Batting.csv'
2027 HBP 1/0/T/F/TRUE/FALSE      5 'core/Batting.csv'
.... ... .................. ...... ..................
See problems(...) for more details.
  1. .Rmd Line numbers for inspecting data intake:
head(HallOfFame)
glimpse(HallOfFame)
head(Salaries)
glimpse(Salaries)
head(Batting)

Data Wrangling (5 out of 8 required)

Description: Students need not use every function and method introduced in STAT 184, but clear demonstration of proficiency should include proper use of 5 out of the following 8 topics from class: (+) various data verbs for general data wrangling like filter, mutate, summarise, arrange, group_by, etc. (+) joins for multiple data tables. (+) spread & gather to stack/unstack variables (+) regular expressions (+) reduction and/or transformation functions like mean, sum, max, min, n(), rank, pmin, etc. (+) user-defined functions (+) loops and control flow (+) machine learning

  1. .Rmd Line number(s) for general data wrangling:
InductedP<-
  HallOfFame%>%
  filter(inducted == "Y")%>%
  select(playerID, yearID)
InductedP
Money<-
  Salaries%>%
  select(teamID, playerID, salary, yearID)
Money
  1. .Rmd Line number(s) for a join operation:
HallMoney<-
  InductedP%>%
  inner_join(Money, by = c("playerID" = "playerID"))
HallMoney
#
AvgHS<- 
  HallMoney%>%
  group_by(playerID)%>%
  mutate(Salary = mean(salary))
AvgHS
#Players in the whole league
WholeLeague <-
  Batting %>%
  filter(G > 20)%>%
  select(playerID, yearID)
WholeLeague
OnlyL<-
  WholeLeague%>%
  select(playerID, yearID)%>%
  inner_join(HallOfFame, by =c("playerID" = "playerID"))%>%
  filter(inducted == "N")
OnlyL
#All salaries for players in the league  
WLeagueS<-
  OnlyL%>%
  inner_join(Money, by =c("playerID" = "playerID"))
WLeagueS
#Average League salary for each player
AvgS<-
  WLeagueS%>%
  group_by(playerID)%>%
  summarise(Salary = mean(salary))
AvgS

This join operation will join the HallOfFame table with the AllstarFull table to help us find the correlation between the players that made the Hall Of Fame and played in All Star Games. We can use this joined data set to figure out commonalities between all of the Hall Of Fame baseball players.


# Join the AllstarFull table with the HallOfFame table
AllStarHallOfFameJoin <-
  AllstarFull %>%
  inner_join(HallOfFame, by = c("playerID" = "playerID"))

# Use data wrangling to alter the table to find the amount of times an inducted players played in All Star Games
AllStarHallOfFameTable <-
  AllStarHallOfFameJoin %>%
  filter(inducted == "Y") %>%
  group_by(playerID, inducted) %>%
  summarise(AppearanceCount = n()) %>%
  arrange(desc(AppearanceCount))
  
AllStarHallOfFameTable
AvgHS%>%
ggplot(aes(x = yearID.y, y = Salary, color = Salary))+
   geom_point()+
   geom_smooth()+
  labs(x = "Year", y = "Salary (millions)")

AvgS%>%
ggplot(aes(x = playerID, y = Salary, color = Salary))+
   geom_point()+
   geom_smooth()+
  labs(x = "Player", y = "Salary (millions)")

The table displayed below uses regular expressions to display the inducted Hall of Fame players who had a batting average of 500 or more in at least 20 games and years that made the achievement. This helps show how good the inducted players are at batting and the years that they did it in.


HallOfFamePlayers <-
  HallOfFame %>%
  filter(inducted == "Y") %>%
  select(playerID, yearID)


HallOfFameBatting <-
  Batting %>%
  inner_join(HallOfFamePlayers, by = c("playerID" = "playerID"))


HallOfFameBatAvg <-
  HallOfFameBatting %>%
  filter(G > 20) %>%
  select(playerID, yearID.x, AB)


HallOfFameOver500 <-
  HallOfFameBatAvg %>%
  extractMatches("^([5-9]{1}[0-9]{2}).*$", AB) %>%
  filter( ! is.na(match1))
HallOfFameOver500

In the graph above, you can notice that the avg homeruns per year of Hall of Famers is lower than the rest of the league. This would indicate that Homeruns are not a crucial statistic in the game of baseball to get you into the Hall of Fame.


AllStarHallOfFameGraphData <-
  AllStarHallOfFameTable %>%
  group_by(AppearanceCount) %>%
  summarise(total = n())

AllStarHallOfFameGraph <-
  AllStarHallOfFameGraphData %>%
  ggplot(aes(x = AppearanceCount, y = total)) +
  geom_bar(stat = "identity", color = "black", fill = "red") +
  geom_hline(aes(yintercept = mean(total)), color = "blue")

AllStarHallOfFameGraph
#Batting stats

BattingAndHallofFame <- 
  Batting %>%
  full_join(HallOfFame, by = c("playerID" = "playerID")) %>%
  filter(inducted == "Y")

#Only Take stats with players having more than 20 games
BattingAndHallofFame <-
  BattingAndHallofFame %>%
    filter(G > 20) 

HallOfFamerHomies <-
  BattingAndHallofFame %>%
    select(yearID.x, H) %>%
    group_by(yearID.x) %>%
    summarise(AvgHsHOF = mean(H)) %>%
    rename(yearID = yearID.x)

EverybodyBatting <-
  Batting %>%
    filter(G > 20) %>%
    summarise(AvgHomeRunPerPlayerEverybody = mean(H))

GraphHomeRuns <-
  Batting %>%
    select(yearID, G, H) %>%
    group_by(yearID) %>%
    filter(G > 20) %>%
    summarise(AvgHsEvery = mean(H))

#Which league has greater HOF chance
LeagueFromAmerican <-
  BattingAndHallofFame %>%
    select(yearID.x, lgID) %>%
    group_by(yearID.x) %>%
    filter(lgID == "AA") %>%
    summarise(American = n()) %>%
    rename(yearID = yearID.x)

LeagueFromNational <-
  BattingAndHallofFame %>%
    select(yearID.x, lgID) %>%
    group_by(yearID.x) %>%
    filter(lgID == "NL") %>%
    summarise(National = n()) %>%
    rename(yearID = yearID.x)

LeagueGraph <-
  LeagueFromAmerican %>%
    full_join(LeagueFromNational, by = c("yearID" = "yearID"))

 
LeagueGraph1 <-
   LeagueGraph %>%
      gather(key = kind, value = Total, American, National)

LeagueGraph1

Graph1 <-
  GraphHomeRuns %>%
    full_join(HallOfFamerHomies, by = c("yearID" = "yearID"))

Graph1.1 <- 
  Graph1 %>%
    gather(key = kind, value = Avg, AvgHsHOF, AvgHsEvery)


ggplot(data=Graph1.1,aes(x=yearID,y=Avg ,fill=kind))+geom_bar(stat='identity',position='stack', width=.9)+ggtitle("HOF Vs Everybody Homeruns")
  

  
  1. .Rmd Line number(s) for a spread or gather operation (or equivalent):

  2. .Rmd Line number(s) for use of regular expressions:

  3. .Rmd Line number(s) for use of reduction and/or transformation functions:

  4. .Rmd Line number(s) for use of user-defined functions:

  5. .Rmd Line number(s) for use of loops and/or control flow:

  6. .Rmd Line number(s) for use of machine learning (not “wrangling” but scored here):

Data Visualization (3 of 5 required)

Description: Students need not use every function and method introduced in STAT 184, but clear demonstration of proficiency should include a range of useful of data visualizations that are (1) relevant to stated research question for the analysis, (2) include at least one effective display of many–at least 3–variables, and (3) include 3 of the following 5 visualization techniques learned in STAT 184: (+) use of multiple geoms such as points, density, lines, segments, boxplots, bar charts, histograms, etc (+) use of multiple aesthetics–not necessarily all in the same graph–such as color, size, shape, x/y position, facets, etc (+) layered graphics such as points and accompanying smoother, points and accompanying boxplots, overlaid density distributions, etc (+) leaflet maps (+) decision tree and/or dendogram displaying machine learning model results

  1. .Rmd Line number(s) for use of mulitple different geoms:

<<<<<<< HEAD


AllStarHallOfFameGraphData <-
  AllStarHallOfFameTable %>%
  group_by(AppearanceCount) %>%
  summarise(total = n())

AllStarHallOfFameGraph <-
  AllStarHallOfFameGraphData %>%
  ggplot(aes(x = AppearanceCount, y = total)) +
  geom_bar(stat = "identity", color = "black", fill = "red") +
  geom_hline(aes(yintercept = mean(total)), color = "blue")

AllStarHallOfFameGraph
AvgHS%>%
ggplot(aes(x = playerID, y = Salary, color = Salary))+
   geom_point()+
   geom_smooth()+
  labs(x = "Player", y = "Salary (millions)")
AvgS%>%
ggplot(aes(x = playerID, y = Salary, color = Salary))+
   geom_point()+
   geom_smooth()+
  labs(x = "Player", y = "Salary (millions)")

======= >>>>>>> eabcccb550c9451f1e1c6844cf07da10fe8e9f03 (B) .Rmd Line number(s) for use of multiple aesthetics:

  1. .Rmd Line number(s) for use of layered graphics:

  2. .Rmd Line number(s) for use of leaflet maps:

  3. .Rmd Line number(s) for use of decision tree or dendogram results:

Other requirements (Nothing for you to report in this Guidance Document)

  1. All data visualizations must be relevant to the stated research question, and the report must include at least one effective display of many–at least 3–variables

  2. Code quality: Code formatting is consistent with Style Guide Appendix of DataComputing eBook. Specifically, all code chunks demonstrate proficiency with (1) meaningful object names (2) proper use of white space especially with respect to infix operators, chain operators, commas, brackets/parens, etc (3) use of <- assignment operator throughout (4) use of meaningful comments.

  3. Narrative quality: The narrative text (1) clearly states one research question that motivates the overall analysis, (2) explains reasoning for each significant step in the analysis and it’s relationship to the research question, (3) explains significant findings and conclusions as they relate to the research question, and (4) is completely free of errors in spelling and grammar

  4. Overall Quality: Submitted project shows significant effort to produce a high-quality and thoughtful analysis that showcases STAT 184 skills. (2) The project must be self-contained, such that the analysis can be entirely rerun without errors. (3) Analysis is coherent, well-organized, and free of extraneous content such as data dumps, unrelated graphs, and other content that is not overtly connected to the research question.

  5. EXTRA CREDIT (1) Project is submitted as a self-contained GitHub Repo (2) project submission is a functioning github.io webpage generated for the project Repo. Note: a link to the GitHub Repo itself will be awarded partial credit, but does not itself qualify as a “webpage” of the analysis.

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKYXV0aG9yOiAiR3JvdXAgNSwgTWF0dGhldyBIaW5lcywgRW1tYW51ZWwgR2Fyem8sIER1c3RpbiBCZWF2ZXIiCmRhdGU6ICI0LzE2LzIwMjAiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCgpgYGB7cn0KIyBsb2FkIG5lY2Vzc2FyeSBwYWNrYWdlcwpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShtb3NhaWMpCmxpYnJhcnkoRGF0YUNvbXB1dGluZykKbGlicmFyeShnZ3Bsb3QyKQpgYGAKCiMgR3VpZGluZyBRdWVzdGlvbgoKV2hhdCBmYWN0b3JzIGFyZSBjb21tb24gYmV0d2VlbiBhbGwgaGFsbCBvZiBmYW1lIE1MQiBiYXNlYmFsbCBwbGF5ZXJzPwoKCiMgUHVycG9zZQoKKlRoaXMgZG9jdW1lbnQgaXMgcmVxdWlyZWQgdG8gaW5kaWNhdGUgd2hlcmUgdmFyaW91cyByZXF1aXJlbWVudHMgY2FuIGJlIGZvdW5kIHdpdGhpbiB5b3VyIEZpbmFsIFByb2plY3QgUmVwb3J0IFJtZC4gIFlvdSBtdXN0KiAqKmluZGljYXRlIGxpbmUgbnVtYmVycyBhcyB0aGV5IGFwcGVhciBpbiB5b3VyIGZpbmFsIFJtZCBkb2N1bWVudCoqICphY2NvbXBhbnlpbmcgZWFjaCBvZiB0aGUgZm9sbG93aW5nIHJlcXVpcmVkIHRhc2tzLiBQb2ludHMgd2lsbCBiZSBkZWR1Y3RlZCBpZiBsaW5lIG51bWJlcnMgYXJlIG1pc3Npbmcgb3IgZGlmZmVyIHNpZ25maWNhbnRseSBmcm9tIHRoZSBzdWJtaXR0ZWQgRmluYWwgUm1kIGRvY3VtZW50LiogIAoKCiMgRmluYWwgUHJvamVjdCBSZXF1aXJlbWVudHMKCgojIyMgRGF0YSBBY2Nlc3MKCipEZXNjcmlwdGlvbjogKDEpIEFuYWx5c2lzIGluY2x1ZGVzIGF0IGxlYXN0IHR3byBkaWZmZXJlbnQgZGF0YSBzb3VyY2VzLiAoMikgUHJpbWFyeSBkYXRhIHNvdXJjZSBtYXkgTk9UIGJlIGxvYWRlZCBmcm9tIGFuIFIgcGFja2FnZS0tdGhvdWdoIHN1cHBvcnRpbmcgZGF0YSBtYXkuICgzKSBBY2Nlc3MgdG8gYWxsIGRhdGEgc291cmNlcyBpcyBjb250YWluZWQgd2l0aGluIHRoZSBhbmFseXNpcy4gKDQpIEltcG9ydGVkIGRhdGEgaXMgaW5zcGVjdGVkIGF0IGJlZ2lubmluZyBvZiBhbmFseXNpcyB1c2luZyBvbmUgb3IgbW9yZSBSIGZ1bmN0aW9uczogZS5nLiwgc3RyLCBnbGltcHNlLCBoZWFkLCB0YWlsLCBuYW1lcywgbnJvdywgZXRjKgoKKEEpIC5SbWQgTGluZSBudW1iZXJzIHdoZXJlIGF0IGxlYXN0IHR3byBkaWZmZXJlbnQgZGF0YSBzb3VyY2VzIGFyZSBpbXBvcnRlZDogIAoKYGBge3IgTG9hZGluZyB0aGUgRGF0YX0KCkhhbGxPZkZhbWUgPC0gcmVhZF9jc3YoImNvcmUvSGFsbE9mRmFtZS5jc3YiKQpBbGxzdGFyRnVsbCA8LSByZWFkX2NzdigiY29yZS9BbGxzdGFyRnVsbC5jc3YiKQpTYWxhcmllcyA8LSByZWFkX2NzdigiY29yZS9TYWxhcmllcy5jc3YiKQpCYXR0aW5nIDwtIHJlYWRfY3N2KCJjb3JlL0JhdHRpbmcuY3N2IikKCmBgYAoKKEIpIC5SbWQgTGluZSBudW1iZXJzIGZvciBpbnNwZWN0aW5nIGRhdGEgaW50YWtlOiAgCmBgYHtyfQpoZWFkKEhhbGxPZkZhbWUpCmBgYAoKYGBge3J9CmdsaW1wc2UoSGFsbE9mRmFtZSkKYGBgCgpgYGB7cn0KaGVhZChTYWxhcmllcykKYGBgCgpgYGB7cn0KZ2xpbXBzZShTYWxhcmllcykKYGBgCmBgYHtyfQpoZWFkKEJhdHRpbmcpCmBgYApgYGB7cn0KCmBgYAoKCiMjIyBEYXRhIFdyYW5nbGluZyAoNSBvdXQgb2YgOCByZXF1aXJlZCkKCipEZXNjcmlwdGlvbjogU3R1ZGVudHMgbmVlZCBub3QgdXNlIGV2ZXJ5IGZ1bmN0aW9uIGFuZCBtZXRob2QgaW50cm9kdWNlZCBpbiBTVEFUIDE4NCwgYnV0IGNsZWFyIGRlbW9uc3RyYXRpb24gb2YgcHJvZmljaWVuY3kgc2hvdWxkIGluY2x1ZGUgcHJvcGVyIHVzZSBvZiA1IG91dCBvZiB0aGUgZm9sbG93aW5nIDggdG9waWNzIGZyb20gY2xhc3M6ICgrKSB2YXJpb3VzIGRhdGEgdmVyYnMgZm9yIGdlbmVyYWwgZGF0YSB3cmFuZ2xpbmcgbGlrZSBmaWx0ZXIsIG11dGF0ZSwgc3VtbWFyaXNlLCBhcnJhbmdlLCBncm91cF9ieSwgZXRjLiAoKykgam9pbnMgZm9yIG11bHRpcGxlIGRhdGEgdGFibGVzLiAoKykgc3ByZWFkICYgZ2F0aGVyIHRvIHN0YWNrL3Vuc3RhY2sgdmFyaWFibGVzICgrKSByZWd1bGFyIGV4cHJlc3Npb25zICgrKSByZWR1Y3Rpb24gYW5kL29yIHRyYW5zZm9ybWF0aW9uIGZ1bmN0aW9ucyBsaWtlIG1lYW4sIHN1bSwgbWF4LCBtaW4sIG4oKSwgcmFuaywgcG1pbiwgZXRjLiAoKykgdXNlci1kZWZpbmVkIGZ1bmN0aW9ucyAoKykgbG9vcHMgYW5kIGNvbnRyb2wgZmxvdyAoKykgbWFjaGluZSBsZWFybmluZyoKCgooQSkgLlJtZCBMaW5lIG51bWJlcihzKSBmb3IgZ2VuZXJhbCBkYXRhIHdyYW5nbGluZzogCmBgYHtyfQoKSW5kdWN0ZWRQPC0KICBIYWxsT2ZGYW1lJT4lCiAgZmlsdGVyKGluZHVjdGVkID09ICJZIiklPiUKICBzZWxlY3QocGxheWVySUQsIHllYXJJRCkKCkluZHVjdGVkUApgYGAKCmBgYHtyfQpNb25leTwtCiAgU2FsYXJpZXMlPiUKICBzZWxlY3QodGVhbUlELCBwbGF5ZXJJRCwgc2FsYXJ5LCB5ZWFySUQpCgpNb25leQpgYGAKCgooQikgLlJtZCBMaW5lIG51bWJlcihzKSBmb3IgYSBqb2luIG9wZXJhdGlvbjogCmBgYHtyfQpIYWxsTW9uZXk8LQogIEluZHVjdGVkUCU+JQogIGlubmVyX2pvaW4oTW9uZXksIGJ5ID0gYygicGxheWVySUQiID0gInBsYXllcklEIikpCkhhbGxNb25leQojCkF2Z0hTPC0gCiAgSGFsbE1vbmV5JT4lCiAgZ3JvdXBfYnkocGxheWVySUQpJT4lCiAgbXV0YXRlKFNhbGFyeSA9IG1lYW4oc2FsYXJ5KSkKQXZnSFMKCiNQbGF5ZXJzIGluIHRoZSB3aG9sZSBsZWFndWUKV2hvbGVMZWFndWUgPC0KICBCYXR0aW5nICU+JQogIGZpbHRlcihHID4gMjApJT4lCiAgc2VsZWN0KHBsYXllcklELCB5ZWFySUQpCldob2xlTGVhZ3VlCgpPbmx5TDwtCiAgV2hvbGVMZWFndWUlPiUKICBzZWxlY3QocGxheWVySUQsIHllYXJJRCklPiUKICBpbm5lcl9qb2luKEhhbGxPZkZhbWUsIGJ5ID1jKCJwbGF5ZXJJRCIgPSAicGxheWVySUQiKSklPiUKICBmaWx0ZXIoaW5kdWN0ZWQgPT0gIk4iKQpPbmx5TAoKI0FsbCBzYWxhcmllcyBmb3IgcGxheWVycyBpbiB0aGUgbGVhZ3VlICAKV0xlYWd1ZVM8LQogIE9ubHlMJT4lCiAgaW5uZXJfam9pbihNb25leSwgYnkgPWMoInBsYXllcklEIiA9ICJwbGF5ZXJJRCIpKQpXTGVhZ3VlUwoKI0F2ZXJhZ2UgTGVhZ3VlIHNhbGFyeSBmb3IgZWFjaCBwbGF5ZXIKQXZnUzwtCiAgV0xlYWd1ZVMlPiUKICBncm91cF9ieShwbGF5ZXJJRCklPiUKICBzdW1tYXJpc2UoU2FsYXJ5ID0gbWVhbihzYWxhcnkpKQpBdmdTCgoKYGBgCgoKCgpUaGlzIGpvaW4gb3BlcmF0aW9uIHdpbGwgam9pbiB0aGUgSGFsbE9mRmFtZSB0YWJsZSB3aXRoIHRoZSBBbGxzdGFyRnVsbCB0YWJsZSB0byBoZWxwIHVzIGZpbmQgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIHBsYXllcnMgdGhhdCBtYWRlIHRoZSBIYWxsIE9mIEZhbWUgYW5kIHBsYXllZCBpbiBBbGwgU3RhciBHYW1lcy4gV2UgY2FuIHVzZSB0aGlzIGpvaW5lZCBkYXRhIHNldCB0byBmaWd1cmUgb3V0IGNvbW1vbmFsaXRpZXMgYmV0d2VlbiBhbGwgb2YgdGhlIEhhbGwgT2YgRmFtZSBiYXNlYmFsbCBwbGF5ZXJzLgpgYGB7cn0KCiMgSm9pbiB0aGUgQWxsc3RhckZ1bGwgdGFibGUgd2l0aCB0aGUgSGFsbE9mRmFtZSB0YWJsZQpBbGxTdGFySGFsbE9mRmFtZUpvaW4gPC0KICBBbGxzdGFyRnVsbCAlPiUKICBpbm5lcl9qb2luKEhhbGxPZkZhbWUsIGJ5ID0gYygicGxheWVySUQiID0gInBsYXllcklEIikpCgojIFVzZSBkYXRhIHdyYW5nbGluZyB0byBhbHRlciB0aGUgdGFibGUgdG8gZmluZCB0aGUgYW1vdW50IG9mIHRpbWVzIGFuIGluZHVjdGVkIHBsYXllcnMgcGxheWVkIGluIEFsbCBTdGFyIEdhbWVzCkFsbFN0YXJIYWxsT2ZGYW1lVGFibGUgPC0KICBBbGxTdGFySGFsbE9mRmFtZUpvaW4gJT4lCiAgZmlsdGVyKGluZHVjdGVkID09ICJZIikgJT4lCiAgZ3JvdXBfYnkocGxheWVySUQsIGluZHVjdGVkKSAlPiUKICBzdW1tYXJpc2UoQXBwZWFyYW5jZUNvdW50ID0gbigpKSAlPiUKICBhcnJhbmdlKGRlc2MoQXBwZWFyYW5jZUNvdW50KSkKICAKQWxsU3RhckhhbGxPZkZhbWVUYWJsZQoKYGBgCgoKYGBge3J9CgpBdmdIUyU+JQpnZ3Bsb3QoYWVzKHggPSB5ZWFySUQueSwgeSA9IFNhbGFyeSwgY29sb3IgPSBTYWxhcnkpKSsKICAgZ2VvbV9wb2ludCgpKwogICBnZW9tX3Ntb290aCgpKwogIGxhYnMoeCA9ICJZZWFyIiwgeSA9ICJTYWxhcnkgKG1pbGxpb25zKSIpCgpgYGAKCgpgYGB7cn0KCkF2Z1MlPiUKZ2dwbG90KGFlcyh4ID0gcGxheWVySUQsIHkgPSBTYWxhcnksIGNvbG9yID0gU2FsYXJ5KSkrCiAgIGdlb21fcG9pbnQoKSsKICAgZ2VvbV9zbW9vdGgoKSsKICBsYWJzKHggPSAiUGxheWVyIiwgeSA9ICJTYWxhcnkgKG1pbGxpb25zKSIpCgpgYGAKClRoZSB0YWJsZSBkaXNwbGF5ZWQgYmVsb3cgdXNlcyByZWd1bGFyIGV4cHJlc3Npb25zIHRvIGRpc3BsYXkgdGhlIGluZHVjdGVkIEhhbGwgb2YgRmFtZSBwbGF5ZXJzIHdobyBoYWQgYSBiYXR0aW5nIGF2ZXJhZ2Ugb2YgNTAwIG9yIG1vcmUgaW4gYXQgbGVhc3QgMjAgZ2FtZXMgYW5kIHllYXJzIHRoYXQgbWFkZSB0aGUgYWNoaWV2ZW1lbnQuIFRoaXMgaGVscHMgc2hvdyBob3cgZ29vZCB0aGUgaW5kdWN0ZWQgcGxheWVycyBhcmUgYXQgYmF0dGluZyBhbmQgdGhlIHllYXJzIHRoYXQgdGhleSBkaWQgaXQgaW4uCmBgYHtyfQoKSGFsbE9mRmFtZVBsYXllcnMgPC0KICBIYWxsT2ZGYW1lICU+JQogIGZpbHRlcihpbmR1Y3RlZCA9PSAiWSIpICU+JQogIHNlbGVjdChwbGF5ZXJJRCwgeWVhcklEKQoKCkhhbGxPZkZhbWVCYXR0aW5nIDwtCiAgQmF0dGluZyAlPiUKICBpbm5lcl9qb2luKEhhbGxPZkZhbWVQbGF5ZXJzLCBieSA9IGMoInBsYXllcklEIiA9ICJwbGF5ZXJJRCIpKQoKCkhhbGxPZkZhbWVCYXRBdmcgPC0KICBIYWxsT2ZGYW1lQmF0dGluZyAlPiUKICBmaWx0ZXIoRyA+IDIwKSAlPiUKICBzZWxlY3QocGxheWVySUQsIHllYXJJRC54LCBBQikKCgpIYWxsT2ZGYW1lT3ZlcjUwMCA8LQogIEhhbGxPZkZhbWVCYXRBdmcgJT4lCiAgZXh0cmFjdE1hdGNoZXMoIl4oWzUtOV17MX1bMC05XXsyfSkuKiQiLCBBQikgJT4lCiAgZmlsdGVyKCAhIGlzLm5hKG1hdGNoMSkpCkhhbGxPZkZhbWVPdmVyNTAwCgpgYGAKCgpJbiB0aGUgZ3JhcGggYWJvdmUsIHlvdSBjYW4gbm90aWNlIHRoYXQgdGhlIGF2ZyBob21lcnVucyBwZXIgeWVhciBvZiBIYWxsIG9mIEZhbWVycyBpcyBsb3dlciB0aGFuIHRoZSByZXN0IG9mIHRoZSBsZWFndWUuIFRoaXMgd291bGQgaW5kaWNhdGUgdGhhdCBIb21lcnVucyBhcmUgbm90IGEgY3J1Y2lhbCBzdGF0aXN0aWMgaW4gdGhlIGdhbWUgb2YgYmFzZWJhbGwgdG8gZ2V0IHlvdSBpbnRvIHRoZSBIYWxsIG9mIEZhbWUuCmBgYHtyfQoKQWxsU3RhckhhbGxPZkZhbWVHcmFwaERhdGEgPC0KICBBbGxTdGFySGFsbE9mRmFtZVRhYmxlICU+JQogIGdyb3VwX2J5KEFwcGVhcmFuY2VDb3VudCkgJT4lCiAgc3VtbWFyaXNlKHRvdGFsID0gbigpKQoKQWxsU3RhckhhbGxPZkZhbWVHcmFwaCA8LQogIEFsbFN0YXJIYWxsT2ZGYW1lR3JhcGhEYXRhICU+JQogIGdncGxvdChhZXMoeCA9IEFwcGVhcmFuY2VDb3VudCwgeSA9IHRvdGFsKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBjb2xvciA9ICJibGFjayIsIGZpbGwgPSAicmVkIikgKwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSBtZWFuKHRvdGFsKSksIGNvbG9yID0gImJsdWUiKQoKQWxsU3RhckhhbGxPZkZhbWVHcmFwaAoKYGBgCgoKCmBgYHtyfQojQmF0dGluZyBzdGF0cwoKQmF0dGluZ0FuZEhhbGxvZkZhbWUgPC0gCiAgQmF0dGluZyAlPiUKICBmdWxsX2pvaW4oSGFsbE9mRmFtZSwgYnkgPSBjKCJwbGF5ZXJJRCIgPSAicGxheWVySUQiKSkgJT4lCiAgZmlsdGVyKGluZHVjdGVkID09ICJZIikKCiNPbmx5IFRha2Ugc3RhdHMgd2l0aCBwbGF5ZXJzIGhhdmluZyBtb3JlIHRoYW4gMjAgZ2FtZXMKQmF0dGluZ0FuZEhhbGxvZkZhbWUgPC0KICBCYXR0aW5nQW5kSGFsbG9mRmFtZSAlPiUKICAgIGZpbHRlcihHID4gMjApIAoKSGFsbE9mRmFtZXJIb21pZXMgPC0KICBCYXR0aW5nQW5kSGFsbG9mRmFtZSAlPiUKICAgIHNlbGVjdCh5ZWFySUQueCwgSCkgJT4lCiAgICBncm91cF9ieSh5ZWFySUQueCkgJT4lCiAgICBzdW1tYXJpc2UoQXZnSHNIT0YgPSBtZWFuKEgpKSAlPiUKICAgIHJlbmFtZSh5ZWFySUQgPSB5ZWFySUQueCkKCkV2ZXJ5Ym9keUJhdHRpbmcgPC0KICBCYXR0aW5nICU+JQogICAgZmlsdGVyKEcgPiAyMCkgJT4lCiAgICBzdW1tYXJpc2UoQXZnSG9tZVJ1blBlclBsYXllckV2ZXJ5Ym9keSA9IG1lYW4oSCkpCgpHcmFwaEhvbWVSdW5zIDwtCiAgQmF0dGluZyAlPiUKICAgIHNlbGVjdCh5ZWFySUQsIEcsIEgpICU+JQogICAgZ3JvdXBfYnkoeWVhcklEKSAlPiUKICAgIGZpbHRlcihHID4gMjApICU+JQogICAgc3VtbWFyaXNlKEF2Z0hzRXZlcnkgPSBtZWFuKEgpKQoKI1doaWNoIGxlYWd1ZSBoYXMgZ3JlYXRlciBIT0YgY2hhbmNlCkxlYWd1ZUZyb21BbWVyaWNhbiA8LQogIEJhdHRpbmdBbmRIYWxsb2ZGYW1lICU+JQogICAgc2VsZWN0KHllYXJJRC54LCBsZ0lEKSAlPiUKICAgIGdyb3VwX2J5KHllYXJJRC54KSAlPiUKICAgIGZpbHRlcihsZ0lEID09ICJBQSIpICU+JQogICAgc3VtbWFyaXNlKEFtZXJpY2FuID0gbigpKSAlPiUKICAgIHJlbmFtZSh5ZWFySUQgPSB5ZWFySUQueCkKCkxlYWd1ZUZyb21OYXRpb25hbCA8LQogIEJhdHRpbmdBbmRIYWxsb2ZGYW1lICU+JQogICAgc2VsZWN0KHllYXJJRC54LCBsZ0lEKSAlPiUKICAgIGdyb3VwX2J5KHllYXJJRC54KSAlPiUKICAgIGZpbHRlcihsZ0lEID09ICJOTCIpICU+JQogICAgc3VtbWFyaXNlKE5hdGlvbmFsID0gbigpKSAlPiUKICAgIHJlbmFtZSh5ZWFySUQgPSB5ZWFySUQueCkKCkxlYWd1ZUdyYXBoIDwtCiAgTGVhZ3VlRnJvbUFtZXJpY2FuICU+JQogICAgZnVsbF9qb2luKExlYWd1ZUZyb21OYXRpb25hbCwgYnkgPSBjKCJ5ZWFySUQiID0gInllYXJJRCIpKQoKIApMZWFndWVHcmFwaDEgPC0KICAgTGVhZ3VlR3JhcGggJT4lCiAgICAgIGdhdGhlcihrZXkgPSBraW5kLCB2YWx1ZSA9IFRvdGFsLCBBbWVyaWNhbiwgTmF0aW9uYWwpCgpMZWFndWVHcmFwaDEKCkdyYXBoMSA8LQogIEdyYXBoSG9tZVJ1bnMgJT4lCiAgICBmdWxsX2pvaW4oSGFsbE9mRmFtZXJIb21pZXMsIGJ5ID0gYygieWVhcklEIiA9ICJ5ZWFySUQiKSkKCkdyYXBoMS4xIDwtIAogIEdyYXBoMSAlPiUKICAgIGdhdGhlcihrZXkgPSBraW5kLCB2YWx1ZSA9IEF2ZywgQXZnSHNIT0YsIEF2Z0hzRXZlcnkpCgoKZ2dwbG90KGRhdGE9R3JhcGgxLjEsYWVzKHg9eWVhcklELHk9QXZnICxmaWxsPWtpbmQpKStnZW9tX2JhcihzdGF0PSdpZGVudGl0eScscG9zaXRpb249J3N0YWNrJywgd2lkdGg9LjkpK2dndGl0bGUoIkhPRiBWcyBFdmVyeWJvZHkgSG9tZXJ1bnMiKQogIAoKICAKCmBgYAoKCgooQykgLlJtZCBMaW5lIG51bWJlcihzKSBmb3IgYSBzcHJlYWQgb3IgZ2F0aGVyIG9wZXJhdGlvbiAob3IgZXF1aXZhbGVudCk6CgoKKEQpIC5SbWQgTGluZSBudW1iZXIocykgZm9yIHVzZSBvZiByZWd1bGFyIGV4cHJlc3Npb25zOiAKCgooRSkgLlJtZCBMaW5lIG51bWJlcihzKSBmb3IgdXNlIG9mIHJlZHVjdGlvbiBhbmQvb3IgdHJhbnNmb3JtYXRpb24gZnVuY3Rpb25zOiAKCgooRikgLlJtZCBMaW5lIG51bWJlcihzKSBmb3IgdXNlIG9mIHVzZXItZGVmaW5lZCBmdW5jdGlvbnM6IAoKCihHKSAuUm1kIExpbmUgbnVtYmVyKHMpIGZvciB1c2Ugb2YgbG9vcHMgYW5kL29yIGNvbnRyb2wgZmxvdzogCgoKKEgpIC5SbWQgTGluZSBudW1iZXIocykgZm9yIHVzZSBvZiBtYWNoaW5lIGxlYXJuaW5nIChub3QgIndyYW5nbGluZyIgYnV0IHNjb3JlZCBoZXJlKTogCgoKCiMjIyBEYXRhIFZpc3VhbGl6YXRpb24gKDMgb2YgNSByZXF1aXJlZCkKCipEZXNjcmlwdGlvbjogU3R1ZGVudHMgbmVlZCBub3QgdXNlIGV2ZXJ5IGZ1bmN0aW9uIGFuZCBtZXRob2QgaW50cm9kdWNlZCBpbiBTVEFUIDE4NCwgYnV0IGNsZWFyIGRlbW9uc3RyYXRpb24gb2YgcHJvZmljaWVuY3kgc2hvdWxkIGluY2x1ZGUgYSByYW5nZSBvZiB1c2VmdWwgb2YgZGF0YSB2aXN1YWxpemF0aW9ucyB0aGF0IGFyZSAoMSkgcmVsZXZhbnQgdG8gc3RhdGVkIHJlc2VhcmNoIHF1ZXN0aW9uIGZvciB0aGUgYW5hbHlzaXMsICgyKSBpbmNsdWRlIGF0IGxlYXN0IG9uZSBlZmZlY3RpdmUgZGlzcGxheSBvZiBtYW55LS1hdCBsZWFzdCAzLS12YXJpYWJsZXMsIGFuZCAoMykgaW5jbHVkZSAzIG9mIHRoZSBmb2xsb3dpbmcgNSB2aXN1YWxpemF0aW9uIHRlY2huaXF1ZXMgbGVhcm5lZCBpbiBTVEFUIDE4NDogKCspIHVzZSBvZiBtdWx0aXBsZSBnZW9tcyBzdWNoIGFzIHBvaW50cywgZGVuc2l0eSwgbGluZXMsIHNlZ21lbnRzLCBib3hwbG90cywgYmFyIGNoYXJ0cywgaGlzdG9ncmFtcywgZXRjICgrKSB1c2Ugb2YgbXVsdGlwbGUgYWVzdGhldGljcy0tbm90IG5lY2Vzc2FyaWx5IGFsbCBpbiB0aGUgc2FtZSBncmFwaC0tc3VjaCBhcyBjb2xvciwgc2l6ZSwgc2hhcGUsIHgveSBwb3NpdGlvbiwgZmFjZXRzLCBldGMgKCspIGxheWVyZWQgZ3JhcGhpY3Mgc3VjaCBhcyBwb2ludHMgYW5kIGFjY29tcGFueWluZyBzbW9vdGhlciwgcG9pbnRzIGFuZCBhY2NvbXBhbnlpbmcgYm94cGxvdHMsIG92ZXJsYWlkIGRlbnNpdHkgZGlzdHJpYnV0aW9ucywgZXRjICgrKSBsZWFmbGV0IG1hcHMgKCspIGRlY2lzaW9uIHRyZWUgYW5kL29yIGRlbmRvZ3JhbSBkaXNwbGF5aW5nIG1hY2hpbmUgbGVhcm5pbmcgbW9kZWwgcmVzdWx0cyoKCgoKCihBKSAuUm1kIExpbmUgbnVtYmVyKHMpIGZvciB1c2Ugb2YgbXVsaXRwbGUgZGlmZmVyZW50IGdlb21zOgoKPDw8PDw8PCBIRUFECmBgYHtyfQoKQWxsU3RhckhhbGxPZkZhbWVHcmFwaERhdGEgPC0KICBBbGxTdGFySGFsbE9mRmFtZVRhYmxlICU+JQogIGdyb3VwX2J5KEFwcGVhcmFuY2VDb3VudCkgJT4lCiAgc3VtbWFyaXNlKHRvdGFsID0gbigpKQoKQWxsU3RhckhhbGxPZkZhbWVHcmFwaCA8LQogIEFsbFN0YXJIYWxsT2ZGYW1lR3JhcGhEYXRhICU+JQogIGdncGxvdChhZXMoeCA9IEFwcGVhcmFuY2VDb3VudCwgeSA9IHRvdGFsKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBjb2xvciA9ICJibGFjayIsIGZpbGwgPSAicmVkIikgKwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSBtZWFuKHRvdGFsKSksIGNvbG9yID0gImJsdWUiKQoKQWxsU3RhckhhbGxPZkZhbWVHcmFwaAoKYGBgCgpgYGB7cn0KQXZnSFMlPiUKZ2dwbG90KGFlcyh4ID0gcGxheWVySUQsIHkgPSBTYWxhcnksIGNvbG9yID0gU2FsYXJ5KSkrCiAgIGdlb21fcG9pbnQoKSsKICAgZ2VvbV9zbW9vdGgoKSsKICBsYWJzKHggPSAiUGxheWVyIiwgeSA9ICJTYWxhcnkgKG1pbGxpb25zKSIpCmBgYApgYGB7cn0KQXZnUyU+JQpnZ3Bsb3QoYWVzKHggPSBwbGF5ZXJJRCwgeSA9IFNhbGFyeSwgY29sb3IgPSBTYWxhcnkpKSsKICAgZ2VvbV9wb2ludCgpKwogICBnZW9tX3Ntb290aCgpKwogIGxhYnMoeCA9ICJQbGF5ZXIiLCB5ID0gIlNhbGFyeSAobWlsbGlvbnMpIikKYGBgCgoKPT09PT09PQo+Pj4+Pj4+IGVhYmNjY2I1NTBjOTQ1MWYxZTFjNjg0NGNmMDdkYTEwZmU4ZTlmMDMKKEIpIC5SbWQgTGluZSBudW1iZXIocykgZm9yIHVzZSBvZiBtdWx0aXBsZSBhZXN0aGV0aWNzOiAgCgooQykgLlJtZCBMaW5lIG51bWJlcihzKSBmb3IgdXNlIG9mIGxheWVyZWQgZ3JhcGhpY3M6ICAKCihEKSAuUm1kIExpbmUgbnVtYmVyKHMpIGZvciB1c2Ugb2YgbGVhZmxldCBtYXBzOiAgCgooRSkgLlJtZCBMaW5lIG51bWJlcihzKSBmb3IgdXNlIG9mIGRlY2lzaW9uIHRyZWUgb3IgZGVuZG9ncmFtIHJlc3VsdHM6ICAgIAoKCgoKIyMjIE90aGVyIHJlcXVpcmVtZW50cyAoTm90aGluZyBmb3IgeW91IHRvIHJlcG9ydCBpbiB0aGlzIEd1aWRhbmNlIERvY3VtZW50KQoKKEEpICpBbGwgZGF0YSB2aXN1YWxpemF0aW9ucyogbXVzdCBiZSByZWxldmFudCB0byB0aGUgc3RhdGVkIHJlc2VhcmNoIHF1ZXN0aW9uLCBhbmQgdGhlIHJlcG9ydCBtdXN0IGluY2x1ZGUgYXQgbGVhc3Qgb25lIGVmZmVjdGl2ZSBkaXNwbGF5IG9mIG1hbnktLWF0IGxlYXN0IDMtLXZhcmlhYmxlcyAKCihCKSAqQ29kZSBxdWFsaXR5OiogQ29kZSBmb3JtYXR0aW5nIGlzIGNvbnNpc3RlbnQgd2l0aCBTdHlsZSBHdWlkZSBBcHBlbmRpeCBvZiBEYXRhQ29tcHV0aW5nIGVCb29rLiBTcGVjaWZpY2FsbHksIGFsbCBjb2RlIGNodW5rcyBkZW1vbnN0cmF0ZSBwcm9maWNpZW5jeSB3aXRoICgxKSBtZWFuaW5nZnVsIG9iamVjdCBuYW1lcyAoMikgcHJvcGVyIHVzZSBvZiB3aGl0ZSBzcGFjZSBlc3BlY2lhbGx5IHdpdGggcmVzcGVjdCB0byBpbmZpeCBvcGVyYXRvcnMsIGNoYWluIG9wZXJhdG9ycywgY29tbWFzLCBicmFja2V0cy9wYXJlbnMsIGV0YyAoMykgdXNlIG9mIGA8LWAgYXNzaWdubWVudCBvcGVyYXRvciB0aHJvdWdob3V0ICg0KSB1c2Ugb2YgbWVhbmluZ2Z1bCBjb21tZW50cy4KCihDKSAqTmFycmF0aXZlIHF1YWxpdHk6KiBUaGUgbmFycmF0aXZlIHRleHQgKDEpIGNsZWFybHkgc3RhdGVzIG9uZSByZXNlYXJjaCBxdWVzdGlvbiB0aGF0IG1vdGl2YXRlcyB0aGUgb3ZlcmFsbCBhbmFseXNpcywgKDIpIGV4cGxhaW5zIHJlYXNvbmluZyBmb3IgZWFjaCBzaWduaWZpY2FudCBzdGVwIGluIHRoZSBhbmFseXNpcyBhbmQgaXQncyByZWxhdGlvbnNoaXAgdG8gdGhlIHJlc2VhcmNoIHF1ZXN0aW9uLCAoMykgZXhwbGFpbnMgc2lnbmlmaWNhbnQgZmluZGluZ3MgYW5kIGNvbmNsdXNpb25zIGFzIHRoZXkgcmVsYXRlIHRvIHRoZSByZXNlYXJjaCBxdWVzdGlvbiwgYW5kICg0KSBpcyBjb21wbGV0ZWx5IGZyZWUgb2YgZXJyb3JzIGluIHNwZWxsaW5nIGFuZCBncmFtbWFyCgooRCkgKk92ZXJhbGwgUXVhbGl0eToqIFN1Ym1pdHRlZCBwcm9qZWN0IHNob3dzIHNpZ25pZmljYW50IGVmZm9ydCB0byBwcm9kdWNlIGEgaGlnaC1xdWFsaXR5IGFuZCB0aG91Z2h0ZnVsIGFuYWx5c2lzIHRoYXQgc2hvd2Nhc2VzIFNUQVQgMTg0IHNraWxscy4gKDIpIFRoZSBwcm9qZWN0IG11c3QgYmUgc2VsZi1jb250YWluZWQsIHN1Y2ggdGhhdCB0aGUgYW5hbHlzaXMgY2FuIGJlIGVudGlyZWx5IHJlcnVuIHdpdGhvdXQgZXJyb3JzLiAoMykgQW5hbHlzaXMgaXMgY29oZXJlbnQsIHdlbGwtb3JnYW5pemVkLCBhbmQgZnJlZSBvZiBleHRyYW5lb3VzIGNvbnRlbnQgc3VjaCBhcyBkYXRhIGR1bXBzLCB1bnJlbGF0ZWQgZ3JhcGhzLCBhbmQgb3RoZXIgY29udGVudCB0aGF0IGlzIG5vdCBvdmVydGx5IGNvbm5lY3RlZCB0byB0aGUgcmVzZWFyY2ggcXVlc3Rpb24uCgooRSkgKkVYVFJBIENSRURJVCogKDEpIFByb2plY3QgaXMgc3VibWl0dGVkIGFzIGEgc2VsZi1jb250YWluZWQgR2l0SHViIFJlcG8gKDIpIHByb2plY3Qgc3VibWlzc2lvbiBpcyBhIGZ1bmN0aW9uaW5nIGdpdGh1Yi5pbyB3ZWJwYWdlIGdlbmVyYXRlZCBmb3IgdGhlIHByb2plY3QgUmVwby4gTm90ZTogYSBsaW5rIHRvIHRoZSBHaXRIdWIgUmVwbyBpdHNlbGYgd2lsbCBiZSBhd2FyZGVkIHBhcnRpYWwgY3JlZGl0LCBidXQgZG9lcyBub3QgaXRzZWxmIHF1YWxpZnkgYXMgYSAid2VicGFnZSIgb2YgdGhlIGFuYWx5c2lzLgo=